package com.vitogiovanni.tobook.entity;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Nullable;
import javax.inject.Named;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.persistence.EntityNotFoundException;

import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiMethod.HttpMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.CollectionResponse;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.datanucleus.query.JDOCursorHelper;
import com.vitogiovanni.tobook.utilities.JsonParser;

@Api(name = "utenteendpoint", namespace = @ApiNamespace(ownerDomain = "vitogiovanni.com", ownerName = "vitogiovanni.com", packagePath = "tobook.entity"))
public class UtenteEndpoint {

	/**
	 * This method lists all the entities inserted in datastore.
	 * It uses HTTP GET method and paging support.
	 *
	 * @return A CollectionResponse class containing the list of all entities
	 * persisted and a cursor to the next page.
	 */
	@SuppressWarnings({ "unchecked", "unused" })
	@ApiMethod(name = "listUtente")
	public CollectionResponse<Utente> listUtente(
			@Nullable @Named("cursor") String cursorString,
			@Nullable @Named("limit") Integer limit) {

		PersistenceManager mgr = null;
		Cursor cursor = null;
		List<Utente> execute = null;

		try {
			mgr = getPersistenceManager();
			Query query = mgr.newQuery(Utente.class);
			if (cursorString != null && cursorString != "") {
				cursor = Cursor.fromWebSafeString(cursorString);
				HashMap<String, Object> extensionMap = new HashMap<String, Object>();
				extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
				query.setExtensions(extensionMap);
			}

			if (limit != null) {
				query.setRange(0, limit);
			}

			execute = (List<Utente>) query.execute();
			cursor = JDOCursorHelper.getCursor(execute);
			if (cursor != null)
				cursorString = cursor.toWebSafeString();

			// Tight loop for fetching all entities from datastore and accomodate
			// for lazy fetch.
			for (Utente obj : execute)
				;
		} finally {
			mgr.close();
		}

		return CollectionResponse.<Utente> builder().setItems(execute)
				.setNextPageToken(cursorString).build();
	}

	/**
	 * This method gets the entity having primary key id. It uses HTTP GET method.
	 *
	 * @param id the primary key of the java bean.
	 * @return The entity with primary key id.
	 */
	@ApiMethod(name = "getUtente")
	public Utente getUtente(@Named("id") Long id) {
		PersistenceManager mgr = getPersistenceManager();
		Utente utente = null;
		try {
			utente = mgr.getObjectById(Utente.class, id);
		} finally {
			mgr.close();
		}
		return utente;
	}

	/**
	 * This inserts a new entity into App Engine datastore. If the entity already
	 * exists in the datastore, an exception is thrown.
	 * It uses HTTP POST method.
	 *
	 * @param utente the entity to be inserted.
	 * @return The inserted entity.
	 */
	@ApiMethod(name = "insertUtente")
	public Utente insertUtente(Utente utente) {
		PersistenceManager mgr = getPersistenceManager();
		try {
			/*if (containsUtente(utente)) {
				throw new EntityExistsException("Object already exists");
			}*/
			mgr.makePersistent(utente);
		} finally {
			mgr.close();
		}
		return utente;
	}

	/**
	 * This method is used for updating an existing entity. If the entity does not
	 * exist in the datastore, an exception is thrown.
	 * It uses HTTP PUT method.
	 *
	 * @param utente the entity to be updated.
	 * @return The updated entity.
	 */
	@ApiMethod(name = "updateUtente")
	public Utente updateUtente(Utente utente) {
		PersistenceManager mgr = getPersistenceManager();
		try {
			if (!containsUtente(utente)) {
				throw new EntityNotFoundException("Object does not exist");
			}
			mgr.makePersistent(utente);
		} finally {
			mgr.close();
		}
		return utente;
	}

	/**
	 * This method removes the entity with primary key id.
	 * It uses HTTP DELETE method.
	 *
	 * @param id the primary key of the entity to be deleted.
	 */
	@ApiMethod(name = "removeUtente")
	public void removeUtente(@Named("id") Long id) {
		PersistenceManager mgr = getPersistenceManager();
		try {
			Utente utente = mgr.getObjectById(Utente.class, id);
			mgr.deletePersistent(utente);
		} finally {
			mgr.close();
		}
	}
	
	
	@SuppressWarnings({ "unchecked", "finally" })
	@ApiMethod(name = "findByEmail", path= "find_utente_by_email", httpMethod=HttpMethod.GET)
	public Utente findByEmail(@Named("email") String email) {

		PersistenceManager mgr = getPersistenceManager();
		List<Utente> utente = null;
		try {
			Query query = mgr.newQuery(Utente.class);
			query.setFilter("email == thatEmail");
			query.declareParameters("String thatEmail");
			Object temp = query.execute(email);
			if(temp != null)
			{
				utente = (List<Utente>) temp;
			}
			else{
				return null;
			}
			if(utente.size()>=1)
			{
				utente.get(0).getLocaliPreferiti();
				utente.get(0).getPrenotazioni();
			}
			else
			{
				return null;
			}

		} finally {
			mgr.close();
			if(utente != null && utente.size()>=1)
			{
				return utente.get(0);
			}
			else
			{
				return null;
			}
		}

	}
	
	@ApiMethod(name = "addPrenotazione", path= "add_prenotazione", httpMethod=HttpMethod.POST)
	public void addPrenotazione(Key keyPrenotazione, @Named("email") String emailUtente) 
	{
		PersistenceManager mgr = getPersistenceManager();
		Utente utente = null;
		try {
			utente = findByEmail(emailUtente);
			if(utente == null)
			{
				utente = insertUtente(new Utente(emailUtente));
				utente.getPrenotazioni().add(keyPrenotazione);
				mgr.makePersistent(utente);
			}
			else
			{
				utente.getPrenotazioni().add(keyPrenotazione);
				mgr.makePersistent(utente);
				
			}
		} finally {
			mgr.close();
		}
	}
	
	
	@ApiMethod(name = "aggiungiPreferito", path= "aggiungi_preferito", httpMethod=HttpMethod.POST)
	public void aggiungiPreferito(@Named("locale") String idLocaleString, @Named("email") String emailUtente)
	{
		Key idLocale = JsonParser.jsonToKey(idLocaleString);
		UtenteEndpoint utenteEndpoint = new UtenteEndpoint();
		Utente utente = utenteEndpoint.findByEmail(emailUtente);
		Set<Key> listaLocali = utente.getLocaliPreferiti();
		if(listaLocali == null)
		{
			listaLocali = new HashSet<Key>();
		}
		if(!listaLocali.contains(idLocale))
		{
			listaLocali.add(idLocale);
		}
		utente.setLocaliPreferiti(listaLocali);
		
		utenteEndpoint.updateUtente(utente);
	}
	
	@ApiMethod(name = "rimuoviPreferito", path= "rimuovi_preferito", httpMethod=HttpMethod.POST)
	public void rimuoviPreferito(@Named("locale") String idLocaleString, @Named("email") String emailUtente)
	{
		Key idLocale = JsonParser.jsonToKey(idLocaleString);
		UtenteEndpoint utenteEndpoint = new UtenteEndpoint();
		Utente utente = utenteEndpoint.findByEmail(emailUtente);
		Set<Key> listaLocali = utente.getLocaliPreferiti();
		if(listaLocali == null)
		{
			listaLocali = new HashSet<Key>();
		}
		if(listaLocali.contains(idLocale))
		{
			listaLocali.remove(idLocale);
		}
		utente.setLocaliPreferiti(listaLocali);
		
		utenteEndpoint.updateUtente(utente);
	}
	
	/*
	@ApiMethod(name = "isPreferito", path= "is_preferito", httpMethod=HttpMethod.POST)
	public boolean isPreferito(@Named("locale") String idLocaleString, @Named("email") String emailUtente)
	{
		Key idLocale = KeyFactory.stringToKey(idLocaleString);
		UtenteEndpoint utenteEndpoint = new UtenteEndpoint();
		Utente utente = utenteEndpoint.findByEmail(emailUtente);
		Set<Key> listaLocali = utente.getLocaliPreferiti();
		if(listaLocali == null)
		{
			return false;
		}
		else
		{
			return listaLocali.contains(idLocale);
		}
	}
	*/
	
	private boolean containsUtente(Utente utente) {
		PersistenceManager mgr = getPersistenceManager();
		boolean contains = true;
		try {
			mgr.getObjectById(Utente.class, utente.getId());
		} catch (javax.jdo.JDOObjectNotFoundException ex) {
			contains = false;
		} finally {
			mgr.close();
		}
		return contains;
	}

	private static PersistenceManager getPersistenceManager() {
		return PMF.get().getPersistenceManager();
	}

}
